#include "InstanceBacklogFamily.h"

const char *InstanceBacklogFamily::SUBDIR = "/set";

InstanceBacklogFamily::InstanceBacklogFamily()
:Instance() {
	capacityCost = NULL;
	upperBound = NULL;
	backlogCost = NULL;
	totalCapacity = NULL;
	demand = NULL;
	holdingCost = NULL;
	resourceCost = NULL;
	setupTime = NULL;
	family = NULL;
	endProducts = NULL;
	successor = NULL;
	successorCount = NULL;
}

InstanceBacklogFamily::~InstanceBacklogFamily() {
	if (capacityCost != NULL)
		delete [] capacityCost;

	if (upperBound != NULL)
		delete [] upperBound;

	if (backlogCost != NULL)
		delete [] backlogCost;

	if (totalCapacity != NULL)
		delete [] totalCapacity;

	if (demand != NULL)
		delete [] demand;

	if (holdingCost != NULL)
		delete [] holdingCost;

	if (resourceCost != NULL)
		delete [] resourceCost;

	if (setupTime != NULL)
		delete [] setupTime;

	if (family != NULL)
		delete [] family;

	if (endProducts != NULL)
		delete [] endProducts;

	if (successorCount != NULL)
		delete [] successorCount;

	if (successor != NULL) {
		for (int j = 0; j < J; j++)
			if (successor[j] != NULL)
				delete [] successor[j];

		delete [] successor;
	}
}

bool InstanceBacklogFamily::load( const char *name ) {

	// Initializing name
	if (name == NULL) {
		cout << "ERROR: unnamed instance" << endl;
		return false;
	}

	int size = strlen(name);
	this->name = new char[size + 1];
	strcpy( this->name, name );

	// Opening file...
	char *path = getPath(name);
	Input in( path );

	if (in.fail()) {
		cout << "ERROR: could not open instance file: " << path << endl;
		return false;
	}

	delete [] path;

	// File is open. Declare variables...
	int je = 0;
	int *tmp;
	double bcFactor;
	double *Pjf;

	// Reading data...
	in >> J;
	in >> Je;
	in >> T;
	in >> M;
	in >> F;
	in >> bcFactor;

	// Reading holding cost...
	holdingCost = new double[J];
	in.readArray( holdingCost, J );

	backlogCost = new double[J*T];
	for (int j = 0; j < J; j++)
		for (int t = 0; t < T; t++)
			backlogCost[ j*T + t ] = holdingCost[j] * bcFactor;

	// Reading demand...
	demand = new double[J*T];
	in.readArray( demand, J*T );

	// Reading capacity cost...
	capacityCost = new double[J*M];
	in.readArray( capacityCost, J*M );

	// Reading capacity...
	totalCapacity = new double[M*T];
	in.readArray( totalCapacity, M*T );

	// Reading setup time...
	setupTime = new double[F*M];
	in.readArray( setupTime, F*M );

	// Reading resource cost...
	resourceCost = new double[J*J];
	in.readArray( resourceCost, J*J );

	tmp = new int[J];
	successor = new int*[J];
	successorCount = new int[J];
	endProducts = new int[Je];
	for (int j = 0; j < J; j++) {
		successorCount[j] = 0;

		for (int k = 0; k < J; k++)
			if (resourceCost[ j*J + k ] > 0)
				tmp[ successorCount[j]++ ] = k;

		if (successorCount[j] > 0) {
			successor[j] = new int[successorCount[j]];
			for (int k = 0; k < successorCount[j]; k++)
				successor[j][k] = tmp[k];
		}
		else {
			successor[j] = NULL;
			endProducts[ je++ ] = j;
		}
	}

	delete [] tmp;

	// Reading product families...
	family = new int[J];
	Pjf = new double[J*F];
	in.readArray( Pjf, J*F );

	for (int j = 0; j < J; j++) {
		family[j] = -1;
		for (int f = 0; f < F; f++)
			if (Pjf[ j*F + f ] > 0.5) {
				family[j] = f;
				break;
			}
	}

	// Reading upper bounds...
	upperBound = new double [J*T];
	in.readArray( upperBound, J*T );

	/*if (in.fail()) {
		cout << "ERROR: instance data unreadable" << endl;
		return false;
	}*/

	// Instance loaded successfully.

	ready = true;
	return true;
}

char* InstanceBacklogFamily::getPath( const char *name ) {
	char *path = new char[ strlen(name) + strlen(DIR) + strlen(EXT) + strlen(SUBDIR) + 2];
	sprintf(path, "%s%s/%s%s", DIR, SUBDIR, name, EXT);
	return path;
}


int InstanceBacklogFamily::getSolutionSize() {
	return F*T;
}

int InstanceBacklogFamily::getSolutionRows() {
	return F;
}

int InstanceBacklogFamily::getFamilyCount() {
	return F;
}

double InstanceBacklogFamily::getCapacityCost( int m, int j ) {
	if (capacityCost != NULL)
		return capacityCost[ j*M + m ];
	return -1;
}

double InstanceBacklogFamily::getUpperBound( int j, int t ) {
	if (upperBound != NULL)
		return upperBound[ j*T + t ];
	return -1;
}

double InstanceBacklogFamily::getBacklogCost( int j, int t ) {
	if (backlogCost != NULL)
		return backlogCost[ j*T + t ];
	return -1;
}

double InstanceBacklogFamily::getTotalCapacity( int m, int t ) {
	if (totalCapacity != NULL)
		return totalCapacity[ m*T + t ];
	return -1;
}

double InstanceBacklogFamily::getDemand( int j, int t ) {
	if (demand != NULL)
		return demand[ j*T + t ];
	return -1;
}

double InstanceBacklogFamily::getHoldingCost( int j ) {
	if (holdingCost != NULL)
		return holdingCost[j];
	return -1;
}

double InstanceBacklogFamily::getResourceCost( int j, int k ) {
	if (resourceCost != NULL)
		return resourceCost[ j*J + k ];
	return -1;
}

double InstanceBacklogFamily::getSetupTime( int m, int f ) {
	if (setupTime != NULL)
		return setupTime[ f*M + m ];
	return -1;
}

int InstanceBacklogFamily::getFamily( int j ) {
	if (family != NULL)
		return family[j];

	return -1;
}

int InstanceBacklogFamily::getEndProduct( int i ) {
	if (endProducts != NULL && i < Je)
		return endProducts[i];
	return -1;
}

int InstanceBacklogFamily::getSuccessor( int j, int i ) {
	if (successor != NULL && i < successorCount[j])
		return successor[j][i];
	return -1;
}

int InstanceBacklogFamily::getSuccessorCount( int j ) {
	if (j < J)
		return successorCount[j];

	return -1;
}

void InstanceBacklogFamily::print() {
	cout << name;
	cout << "Products:\t" << J << endl <<
			"End Products:\t" << Je << endl <<
			"Periods:\t" << T << endl <<
			"Machines:\t" << M << endl <<
			"Families:\t" << F << endl << endl;

	cout << "Capacity Cost A[m,j]" << endl;
	for (int m = 0; m < M; m++) {
		for (int j = 0; j < J; j++)
			cout << getCapacityCost(m,j) << ' ';

		cout << endl;
	}
	cout << endl;

	cout << "Demand D[j,t]" << endl;
	for (int j = 0; j < J; j++) {
		for (int t = 0; t < T; t++)
			cout << getDemand(j,t) << ' ';

		cout << endl;
	}
	cout << endl;

	cout << "Resource Cost R[j,k]" << endl;
	for (int j = 0; j < J; j++) {
		for (int k = 0; k < J; k++)
			cout << getResourceCost(j,k) << ' ';

		cout << endl;
	}
	cout << endl;

	cout << "Family P[j]" << endl;
	for (int j = 0; j < J; j++) {
		cout << getFamily(j) << ' ';
	}
	cout << endl;
}